import requests
import time
from lxml import etree

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0",
    "content-type": "application/x-www-form-urlencoded",
}
url = "https://music.163.com/discover/playlist/"
params = {
    "order": "hot",
    "cat": "全部",
    "limit": "35",
    "offset": "0",
}

# 获取所有音乐类型
response = requests.get(url, params=params, headers=headers)
html_str = response.content.decode()
root = etree.HTML(html_str)
music_list = root.xpath("//div[@class='bd']/dl[@class='f-cb']/dd")
result_type_list = [music.xpath("./a/text()")[0] for music in music_list if music.xpath("./a/text()")]
print("所有音乐类型:", result_type_list)

error_list = []  # 存储出错页面的列表
total_songs = 0  # 全局总数据量（改用更清晰的变量名）

for data in result_type_list:
    page = 0
    type_count = 0  # 当前类型的计数
    while True:
        refresh_count = 0  # 每页单独的重试计数器
        while True:  # 单页重试逻辑
            try:
                params["offset"] = str(page * 35)
                params["cat"] = data
                response = requests.get(url, params=params, headers=headers, timeout=10)
                html_str = response.content.decode()
                root = etree.HTML(html_str)
                music_list = root.xpath("//div[@class='g-wrap p-pl f-pr']/ul/li")
                if not music_list:
                    raise ValueError("音乐列表为空")

                print(f"当前类型: {data}, 第{page + 1}页, 歌单数: {len(music_list)}")
                for music in music_list:
                    music_title = "".join(music.xpath(".//p[@class='dec']/a/text()")).strip()
                    music_url = "https://music.163.com/#" + "".join(music.xpath(".//p[@class='dec']/a/@href"))
                    music_author = "".join(music.xpath(".//a[@class='nm nm-icn f-thide s-fc3']/text()")).strip()
                    music_plays = "".join(music.xpath(".//div[@class='bottom']/span[@class='nb']/text()")).strip()
                    print(f"歌单名: {music_title}, 作者: {music_author}, 播放量: {music_plays}, 链接: {music_url}")

                type_count += len(music_list)
                total_songs += len(music_list)
                break  # 成功则跳出重试循环

            except Exception as e:
                refresh_count += 1
                print(f"第{page + 1}页第{refresh_count}次重试，错误: {e}")
                if refresh_count >= 5:
                    error_list.append(page)
                    print(f"跳过第{page + 1}页")
                    break  # 跳出重试循环，进入下一页
                time.sleep(3)  # 重试间隔

        # 翻页逻辑
        page += 1
        print(f"当前类型 {data} 已爬取 {type_count} 条，总数据量: {total_songs} 条")

        # 终止条件
        if len(music_list) < int(params["limit"]):
            print(f"类型 {data} 爬取完成，问题页: {error_list}")
            break

        time.sleep(2)  # 翻页间隔